<?php
/*
 * @ https://EasyToYou.eu - IonCube v11 Decoder Online
 * @ PHP 7.2 & 7.3
 * @ Decoder version: 1.1.6
 * @ Release: 10/08/2022
 */

// Decoded file for php version 71.
namespace longbingcore\heepay;

class RtSm21
{
    protected $adapter;
    protected $generator;
    protected $userId = "1234567812345678";
    protected $useDerandomizedSignatures = true;
    protected $useDerandomizedEncrypt = true;
    protected $formatSign = "hex";
    protected $arrFormat = ["hex", "base64"];
    protected $foreignKey = ["21fbd478026e2d668e3570e514de0d312e443d1e294c1ca785dfbfb5f74de225", "04e27c3780e7069bda7082a23a489d77587ce309583ed99253f66e1d9833ed1a1d0b5ce86dc6714e9974cf258589139d7b1855e8c9fa2f2c1175ee123a95a23e9b"];
    protected $cipher;
    public function __construct($formatSign = "hex", $randFixed = true)
    {
        $this->adapter = \Rtgm\ecc\RtEccFactory::getAdapter();
        $this->generator = \Rtgm\ecc\RtEccFactory::getSmCurves()->generatorSm2();
        if(in_array($formatSign, $this->arrFormat)) {
            $this->formatSign = $formatSign;
        } else {
            $this->formatSign = "hex";
        }
        if(!$randFixed) {
            $this->useDerandomizedSignatures = false;
            $this->useDerandomizedEncrypt = false;
        }
    }
    public function generatekey()
    {
        $generator = $this->generator;
        $private = $generator->createPrivateKey();
        $privateKey = $this->decHex($private->getSecret());
        $pubPoint = $private->getPublicKey()->getPoint();
        $pubX = $this->decHex($pubPoint->getX());
        $pubY = $this->decHex($pubPoint->getY());
        $publicKey = "04" . $pubX . $pubY;
        return [$privateKey, $publicKey];
    }
    public function generatePemkey()
    {
        $adapter = $this->adapter;
        $generator = $this->generator;
        $private = $generator->createPrivateKey();
        $derSerializer = new \Mdanter\Ecc\Serializer\PrivateKey\DerPrivateKeySerializer($adapter);
        $pemSerializer = new \Mdanter\Ecc\Serializer\PrivateKey\PemPrivateKeySerializer($derSerializer);
        $privateKeyPem = $pemSerializer->serialize($private);
        $derPubSerializer = new \Mdanter\Ecc\Serializer\PublicKey\DerPublicKeySerializer($adapter);
        $pemPubSerializer = new \Mdanter\Ecc\Serializer\PublicKey\PemPublicKeySerializer($derPubSerializer);
        $publicKeyPem = $pemPubSerializer->serialize($private->getPublicKey());
        return [$privateKeyPem, $publicKeyPem];
    }
    public function doEncrypt($document, $publicKey)
    {
        $adapter = $this->adapter;
        $generator = $this->generator;
        $this->cipher = new \Rtgm\smecc\SM2\Cipher();
        $arrMsg = \Rtgm\smecc\SM2\Hex2ByteBuf::HexStringToByteArray2(bin2hex($document));
        list($pubKeyX, $pubKeyY) = $this->_getKeyXY($publicKey);
        $point = new \Mdanter\Ecc\Primitives\Point($adapter, $generator->getCurve(), gmp_init($pubKeyX, 16), gmp_init($pubKeyY, 16));
        if($this->useDerandomizedEncrypt) {
            $c1 = $this->cipher->initEncipher($point, $this->foreignKey);
        } else {
            $c1 = $this->cipher->initEncipher($point, NULL);
        }
        $arrMsg = $this->cipher->encryptBlock($arrMsg);
        $c2 = strtolower(\Rtgm\smecc\SM2\Hex2ByteBuf::ByteArrayToHexString($arrMsg));
        $c3 = strtolower(\Rtgm\smecc\SM2\Hex2ByteBuf::ByteArrayToHexString($this->cipher->Dofinal()));
        return $c1 . $c3 . $c2;
    }
    public function doDecrypt($encryptData, $privateKey, $trim = true)
    {
        if(substr($encryptData, 0, 2) == "04" && $trim) {
            $encryptData = substr($encryptData, 2);
        }
        $adapter = $this->adapter;
        $generator = $this->generator;
        $this->cipher = new \Rtgm\smecc\SM2\Cipher();
        $c1X = substr($encryptData, 0, 64);
        $c1Y = substr($encryptData, strlen($c1X), 64);
        $c1Length = strlen($c1X) + strlen($c1Y);
        $c3 = substr($encryptData, $c1Length, 64);
        $c2 = substr($encryptData, $c1Length + strlen($c3));
        $p1 = new \Mdanter\Ecc\Primitives\Point($adapter, $generator->getCurve(), gmp_init($c1X, 16), gmp_init($c1Y, 16));
        $this->cipher->initDecipher($p1, $privateKey);
        $arrMsg = \Rtgm\smecc\SM2\Hex2ByteBuf::HexStringToByteArray2($c2);
        $arrMsg = $this->cipher->decryptBlock($arrMsg);
        $document = hex2bin(\Rtgm\smecc\SM2\Hex2ByteBuf::ByteArrayToHexString($arrMsg));
        $c3_ = strtolower(\Rtgm\smecc\SM2\Hex2ByteBuf::ByteArrayToHexString($this->cipher->Dofinal()));
        if($c3 == $c3_) {
            return $document;
        }
        return "";
    }
    public function doSign($document, $privateKey, $userId = NULL)
    {
        if(empty($userId)) {
            $userId = $this->userId;
        }
        $adapter = $this->adapter;
        $generator = $this->generator;
        $algorithm = "sha256";
        $secret = gmp_init($privateKey, 16);
        $key = new \Mdanter\Ecc\Crypto\Key\PrivateKey($adapter, $generator, $secret);
        return $this->_dosign($document, $key, $adapter, $generator, $userId, $algorithm);
    }
    public function doSignOutKey($document, $privateKeyFile, $userId = NULL)
    {
        if(empty($userId)) {
            $userId = $this->userId;
        }
        if(!file_exists($privateKeyFile)) {
            throw new \Exception("privatekey file not exists");
        }
        $adapter = $this->adapter;
        $generator = $this->generator;
        $algorithm = "sha256";
        $pemSerializer = new \Mdanter\Ecc\Serializer\PrivateKey\PemPrivateKeySerializer(new \Mdanter\Ecc\Serializer\PrivateKey\DerPrivateKeySerializer($adapter));
        $keyData = file_get_contents($privateKeyFile);
        $key = $pemSerializer->parse($keyData);
        return $this->_dosign($document, $key, $adapter, $generator, $userId, $algorithm);
    }
    protected function _dosign($document, $key, $adapter, $generator, $userId, $algorithm = "sha256")
    {
        $obPoint = $key->getPublicKey()->getPoint();
        $pubKeyX = $adapter->decHex($obPoint->getX());
        $pubKeyY = $adapter->decHex($obPoint->getY());
        $hash = $this->_doS3Hash($document, $pubKeyX, $pubKeyY, $generator, $userId);
        if($this->useDerandomizedSignatures) {
            $random = \Mdanter\Ecc\Random\RandomGeneratorFactory::getHmacRandomGenerator($key, $hash, $algorithm);
        } else {
            $random = \Mdanter\Ecc\Random\RandomGeneratorFactory::getRandomGenerator();
        }
        $randomK = $random->generate($generator->getOrder());
        $signer = new \Rtgm\ecc\Sm2Signer($adapter);
        $signature = $signer->sign($key, $hash, $randomK);
        $serializer = new \Mdanter\Ecc\Serializer\Signature\DerSignatureSerializer();
        $serializedSig = $serializer->serialize($signature);
        if($this->formatSign == "hex") {
            return bin2hex($serializedSig);
        }
        if($this->formatSign == "base64") {
            return base64_encode($serializedSig) . PHP_EOL;
        }
        return bin2hex($serializedSig);
    }
    public function verifySign($document, $sign, $publicKey, $userId = NULL)
    {
        $adapter = $this->adapter;
        $generator = $this->generator;
        if(empty($userId)) {
            $userId = $this->userId;
        }
        if($this->formatSign == "hex") {
            $sigData = hex2bin($sign);
        } elseif($this->formatSign == "base64") {
            $sigData = base64_decode($sign);
        } else {
            $sigData = hex2bin($sign);
        }
        $sigSerializer = new \Mdanter\Ecc\Serializer\Signature\DerSignatureSerializer();
        $sig = $sigSerializer->parse($sigData);
        list($pubKeyX, $pubKeyY) = $this->_getKeyXY($publicKey);
        $hash = $this->_doS3Hash($document, $pubKeyX, $pubKeyY, $generator, $userId);
        $key = $this->_getPubKeyObject($pubKeyX, $pubKeyY);
        $signer = new \Rtgm\ecc\Sm2Signer($adapter);
        return $signer->verify($key, $sig, $hash);
    }
    public function verifySignOutKey($document, $sign, $publickeyFile, $userId = NULL)
    {
        if(empty($userId)) {
            $userId = $this->userId;
        }
        if(!file_exists($publickeyFile)) {
            throw new \Exception("publickey file not exists");
        }
        $adapter = $this->adapter;
        $generator = $this->generator;
        if($this->formatSign == "hex") {
            $sigData = hex2bin($sign);
        } elseif($this->formatSign == "base64") {
            $sigData = base64_decode($sign);
        } else {
            $sigData = hex2bin($sign);
        }
        $sigSerializer = new \Mdanter\Ecc\Serializer\Signature\DerSignatureSerializer();
        $sig = $sigSerializer->parse($sigData);
        $keyData = file_get_contents($publickeyFile);
        $derSerializer = new \Mdanter\Ecc\Serializer\PublicKey\DerPublicKeySerializer($adapter);
        $pemSerializer = new \Mdanter\Ecc\Serializer\PublicKey\PemPublicKeySerializer($derSerializer);
        $key = $pemSerializer->parse($keyData);
        $pubKeyX = $this->decHex($key->getPoint()->getX());
        $pubKeyY = $this->decHex($key->getPoint()->getY());
        $hash = $this->_doS3Hash($document, $pubKeyX, $pubKeyY, $generator, $userId);
        $signer = new \Rtgm\ecc\Sm2Signer($adapter);
        return $signer->verify($key, $sig, $hash);
    }
    protected function _doS3Hash($document, $pubKeyX, $pubKeyY, $generator, $userId)
    {
        $hasher = new \Rtgm\smecc\SM2\Sm2WithSm3();
        $hash = $hasher->getSm3Hash($document, $pubKeyX, $pubKeyY, $generator, $userId);
        return gmp_init(\Rtgm\smecc\SM2\Hex2ByteBuf::ByteArrayToHexString($hash), 16);
    }
    protected function _getKeyXY($publicKey)
    {
        if(strlen($publicKey) == 128) {
            $pubKeyX = substr($publicKey, 0, 64);
            $pubKeyY = substr($publicKey, -64);
        } elseif(strlen($publicKey) == 130 && substr($publicKey, 0, 2) == "04") {
            $pubKeyX = substr($publicKey, 2, 64);
            $pubKeyY = substr($publicKey, -64);
        } else {
            throw new \Exception("publickey format error");
        }
        return [$pubKeyX, $pubKeyY];
    }
    protected function _getPubKeyObject($pubKeyX, $pubKeyY)
    {
        $generator = $this->generator;
        $x = gmp_init($pubKeyX, 16);
        $y = gmp_init($pubKeyY, 16);
        $point = new \Mdanter\Ecc\Primitives\Point($this->adapter, $generator->getCurve(), $x, $y);
        return new \Mdanter\Ecc\Crypto\Key\PublicKey($this->adapter, $this->generator, $point);
    }
    protected function _str2hex($str)
    {
        $res = [];
        for ($i = 0; $i < strlen($str); $i++) {
            $res[$i] = sprintf("%02x", ord($str[$i]));
        }
        return implode("", $res);
    }
    private function decHex($dec = 64, $len)
    {
        if(gettype($dec) == "string") {
            $dec = gmp_init($dec, 10);
        }
        if(gmp_cmp($dec, 0) < 0) {
            throw new \InvalidArgumentException("Unable to convert negative integer to string");
        }
        $hex = gmp_strval($dec, 16);
        $left = $len - strlen($hex);
        if(0 < $left) {
            $hex = str_repeat("0", $left) . $hex;
        }
        return $hex;
    }
}

?>